﻿using Newtonsoft.Json;

using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices.ComTypes;

using Utils;

namespace System
{
    public class AutoEnumConverter : JsonConverter
    {
        /// <summary>
        /// 枚举类型
        /// </summary>
        private readonly List<EnumInfo> enumValues;

        private readonly bool isFlag = false;
        public AutoEnumConverter(Type enumType)
        {
            enumValues = EnumUtil.GetEnums(enumType);
            isFlag = enumType.GetCustomAttribute<FlagsAttribute>() != null;
        }
        public override bool CanConvert(Type objectType)
        {
            return objectType.IsValueType || objectType.Equals(typeof(string));
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            return serializer.Deserialize(reader, objectType) ?? existingValue;
        }

        private IEnumerable<KeyValuePair<string, object>> GetPropertyValues(string propertyName, object value)
        {
            if (isFlag && (value is int vint))
            {
                return enumValues.Where(a => (vint & a.Value) > 0)
                    .SelectMany(a => GetPropertyValue(a, propertyName, false)).GroupBy(a => a.Key)
                    .Select(a => new KeyValuePair<string, object>(a.Key, a.Select(b => b.Value).ToArray()));
            }
            if (value is string str)
            {
                return enumValues.Where(a => a.Name.Equals(value)).SelectMany(a => GetPropertyValue(a, propertyName, true));
            }
            return enumValues.Where(a => a.Value.Equals(value)).SelectMany(a => GetPropertyValue(a, propertyName, false));
        }


        private Dictionary<string, object> GetPropertyValue(EnumInfo enumInfo, string propertyName, bool hideName)
        {
            Dictionary<string, object> appends = new Dictionary<string, object>();
            if (!hideName)
            {
                appends.Add(propertyName + "Name", enumInfo.Name);
            }
            if (!enumInfo.Description.IsNullOrEmpty())
            {
                appends.Add(propertyName + "Description", enumInfo.Description);
            }
            if (enumInfo.Extends != null)
                foreach (var item in enumInfo.Extends)
                {
                    appends.Add(propertyName + item.Key, item.Value);
                }
            return appends;
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            serializer.Serialize(writer, value);
            if (value != null)
            {
                var propertyName = writer.Path.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries).Last();
                var dict = GetPropertyValues(propertyName, value);
                foreach (var item in dict)
                {
                    writer.WritePropertyName(item.Key);
                    serializer.Serialize(writer, item.Value);
                }
            }
        }
    }
}
